#include<iostream>
#include<vector>
#include<memory>
#include<string>
#include<unordered_map>
using namespace std;

// 抽象享元类
class ChessPiece {
    public:
        virtual void draw(int x, int y) const = 0;//外部状态：坐标
        virtual ~ChessPiece() = default;
};

// 具体享元类
class ConcreteChessPiece : public ChessPiece {
    private:
        string color; // 内部状态:颜色
    public:
        explicit ConcreteChessPiece(const string &c) : color(c) {}
        void draw(int x, int y) const override
        {
            cout << "Draw a " << color << " piece at (" << x << ", " << y << ")\n";
        }
};

// 享元工厂类
class ChessFactory {
    private:
        unordered_map<string, shared_ptr<ChessPiece>> pieces;
    public:
        shared_ptr<ChessPiece> getPiece(const string &color) {
            // 检查是否已有该颜色的棋子
            if (pieces.find(color) == pieces.end()) {
                // 如果没有，则创建一个新的享元对象并存储
                pieces[color] = make_shared<ConcreteChessPiece>(color);
                cout << "[Create new " << color << " piece type]\n";
            }
            return pieces[color];
        }
};

//外部状态类
struct Position
{
    int x, y;
    shared_ptr<ChessPiece> piece;

    Position(int x, int y, shared_ptr<ChessPiece> p)
        : x(x), y(y), piece(p) {}

    void draw() const { piece->draw(x, y); }
};

// 客户端代码
class ChessBoard
{
private:
    vector<Position> positions;
    ChessFactory factory;

public:
    void placePiece(const string &color, int x, int y)
    {
        auto piece = factory.getPiece(color); // 共享对象
        positions.emplace_back(x, y, piece);
    }

    void draw() const
    {
        cout << "\n--- Drawing ChessBoard ---\n";
        for (const auto &pos : positions)
            pos.draw();
    }
};

// ====================== 测试 ======================
int main()
{
    ChessBoard board;

    // 落子
    board.placePiece("Black", 7, 7);
    board.placePiece("White", 7, 8);
    board.placePiece("Black", 8, 8);
    board.placePiece("White", 8, 9);
    board.placePiece("Black", 9, 9); // 五子棋只用两个享元对象

    // 绘制棋盘
    board.draw();

    return 0;
}